perm filename IO.PAL[2,VDS] blob
sn#194115 filedate 1975-12-29 generic text, type C, neo UTF8
COMMENT ā VALID 00018 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 IO - TELETYPE IO AND STRING MANIPULATION ROUTINES
C00006 00003 "INSTR" - VT05 INPUT ROUTINE
C00009 00004 "HOLD" - VT05 ROUTINE TO TEMPORARILY SUSPEND PRINTING
C00010 00005 "RELSCN"- STRING TO FLOATING POINT NUMBER ROUTINE
C00013 00006 [CONTINUATION OF "RELSCN"]
C00016 00007 [CONTINUATION OF "RELSCN"]
C00019 00008 "INTSCN"- STRING TO INTEGER NUMBER ROUTINE
C00021 00009 "CLRCMA"- ROUTINE TO CLEAR COMMA BREAK CHARACTER FROM STRING
C00022 00010 "IDENT" - DECODES STRING COMMAND INTO FUNCTION NUMBER
C00027 00011 "FORMAT"&"RSTFOR" - ROUTINES TO SET AND RESTORE OUTPUT FORMAT
C00029 00012 "CVF" - FLOATING POINT NUMBER TO "F" FORMAT STRING ROUTINE
C00032 00013 "CVE" - FLOATING POINT NUMBER TO "E" FORMAT STRING ROUTINE
C00035 00014 [CONTINUATION OF "CVE"]
C00037 00015 "CVG" - FLOATING POINT NUMBER TO "E" OR "F" FORMAT STRING
C00039 00016 "PRTF" - PRINTING ROUTINE USED BY "CVF", "CVE", & "CVG"
C00042 00017 "CVI"&"CVO" - INTEGER NUMBER TO ASC STRING
C00045 00018 LOCAL STORAGE AREA
C00049 ENDMK
Cā;
;IO - TELETYPE IO AND STRING MANIPULATION ROUTINES
.TITLE IO
;"OUTSTR" IS A MACRO USED FOR PRINTING OUT A STRING ON THE TELETYPE. A
;SAMPLE INSTRUCTION USING THIS MACRO FOLLOWS:
;
; OUTSTR COMMENT
;
;WHERE COMMENT IS THE STARTING ADDRESS OF A ASCII STRING THAT IS TO BE
;WRITTEN. THE STRING TERMINATOR MUST BE A NULL CHARACTER ( 0 ). NO
;REGISTERS ARE AFFECTED BY THIS MACRO CALL.
.MACRO OUTSTR B ;Type string starting at B.
MOV SG,-(SP) ;Save R5. Who knows what was happening in it?
MOV #B,SG ;Load up the string to be output
JSR PC,TYPSTR ;Call the string output utility routine.
MOV (SP)+,SG ;Restore SG.
.ENDM
;"CRLF" IS A SUBROUTINE FOR TYPING OUT ONE CARRIAGE RETURN AND LINE FEED
;ON THE TELETYPE.
CRLF: MOV #CRLFX,SG
JSR PC,TYPSTR
RTS PC
CRLFX: .BYTE 15,12,0,0
;"TYPSTR" OUTPUTS A STRING, ENDING WITH A ZERO CHARACTER. A POINTER TO
;THE START OF THE STRING MUST BE LOADED INTO R5. CALLED USING THE PC.
TYPSTR: MOV R0,-(SP)
MOVB (SG)+,R0 ;R0 ā first byte of string
TSLOOP: JSR PC,TYPCHR ;Type this one character
MOVB (SG)+,R0 ;R0 ā Next byte of string
BNE TSLOOP ;If more to come, repeat.
MOV (SP)+,R0
RTS PC ;Done
TYPCHR: TSTB KBOS ;Is TTY available?
BPL TYPCHR ;No. Busy wait for it.
MOVB R0,KBOR ;Yes. Output a byte to it.
CMP #12,R0 ;Was it a line feed?
BNE TYPRET ;If not that code, then done.
CLR R0 ;Otherwise, output 3 nulls.
JSR PC,TYPCHR ;
JSR PC,TYPCHR ;
JSR PC,TYPCHR ;
TYPRET: RTS PC ;Return.
;"INSTR" - VT05 INPUT ROUTINE
;STRING BYTE POINTER MUST BE IN SG. A CARRIAGE RETURN IS ASSUMED TO
;BE THE ACTIVATION CHARACTER. A RUB OUT IS A DELETING BACKSPACE
;CHARACTER. AT THE COMPLETION OF THIS ROUTINE A NULL CHARACTER IS
;PLACED IN THE INPUT STRING. SG THEN POINTS TO THE NULL CHARACTER.
;REGISTERS USED:
;
; SG PASSES ARGUMENT AND IS MODIFIED
INSTR: MOV R0,-(SP)
CLR CCNT ;RESET CHARACTER COUNT
IN2: TSTB KBIS ;TEST IF KEYBOARD READY
BEQ .-4 ;WAIT TILL IT IS
MOVB KBIR,R0 ;GET A CHARACTER
BIC #177600,R0 ;MASK OFF - MAKE IT 7 BITS
CMP R0,#177 ;COMPARE TO BS CHARACTER
BNE IN3 ;SKIP IF ITS NOT
TST CCNT ;CHECK IF ANY CHARACTERS IN BUFFER
BEQ IN2 ;FORGET BACK SPACE IF NO CHAR.
DEC SG ;REMOVE LAST CHARACTER IN BUFFER
DEC CCNT ;DECREMENT CHARACTER COUNT
OUTSTR DBS ;PERFORM A DELETING BACKSPACE
JMP IN2
IN3: CMP R0,#15 ;COMPARE TO CR CHARACTER
BEQ IN4 ;CONTINUE READING IF ITS NOT A CR
CMP R0,#40 ;CHECK IF CHARACTER LEGAL
BLT IN2 ;IGNOR IF IT IS
MOVB R0,(SG)+ ;SAVE THE CHARACTER
INC CCNT ;INCREMENT CHARACTER COUNT
TSTB KBOS ;ECHO THE CHARACTER
BPL .-4 ;WAIT TILL TTY READY
MOVB R0,KBOR ;WRITE THE CHARACTER
JMP IN2 ;CONTINUE READING
IN4: MOV SG,-(SP) ;IF IT IS A CR, TYPE A CR AND LF
JSR PC,CRLF
MOV (SP)+,SG
MOVB R0,(SG)+ ;PUT A CR IN THE STRING
MOVB #0,(SG) ;PUT IN A NULL CHARACTER
MOV (SP)+,R0
RTS PC ;RETURN
CCNT: 0
DBS: .BYTE 10,40,10,0
;"HOLD" - VT05 ROUTINE TO TEMPORARILY SUSPEND PRINTING
;IF A CHARACTER HAS BEEN TYPED ON THE VT05 KEYBOARD, THIS ROUTINE GOES
;INTO A BUSY WAIT LOOP UNTIL ANOTHER CHARACTER IS TYPED. BOTH CHARACTERS
;ARE LOST. IF NO CHARACTER HAS BEEN TYPED, THIS ROUTINE RETURNS
;IMMEDIATELY.
;REGISTERS USED:
;
; NONE
HOLD: TSTB KBIS ;TEST IF CHARACTER TYPED
BEQ HLDDNE ;RETURN IF NO CHARACTER
CLRB KBIR
TSTB KBIS ;ELSE WAIT TILL ANOTHER CHARACTER TYPED
BEQ .-4
CLRB KBIR
HLDDNE: RTS PC
;END OF "HOLD"
;"RELSCN"- STRING TO FLOATING POINT NUMBER ROUTINE
;THE FLOATING POINT NUMBER MUST BE OF THE FORM SIII.DDDESXX WHERE S IS
;THE SIGN OF THE NUMBER, III IS THE INTEGER FIELD, DDD IS THE DECIMAL
;FIELD, AND SXX IS THE EXPONENT AND ITS SIGN. THE LENGTH OF EACH
;FIELD IS VARIABLE BUT ONLY THE FIRST 8 DIGITS ARE USED IN COMPUTING
;THE F.P. NUMBER. EMPTY FIELDS ARE PERMITTED AND ALL LEADING SPACES
;AND ZEROS ARE IGNORED. THE LOCATION OF THE FIRST BYTE OF THE STRING
;MUST BE LOADED INTO SG BEFORE CALLING "RELSCN". AFTER EXECUTION,
;THIS ROUTINE LEAVES THE F.P. NUMBER IN REGISTER AC0 AND SG POINTS TO
;THE BYTE FOLLOWING THE LAST DIGIT. THE C BIT IS USED TO INDICATE AN
;ERROR CONDITION. IF NO NUMBER WAS FOUND BEFORE ENCOUNTERING A COMMA
;OR NULL CHARACTER, THE C BIT IS SET OTHERWISE THE C BIT IS CLEARED ON
;EXITING THIS ROUTINE. "RELSCN" IS CALLED USING THE PC.
;REGISTERS USED:
;
; AC0,SG PASS ARGUMENTS, NO OTHER REGISTERS AFFECTED
;"DIGIT" CHECKS FOR ASC DIGIT AND CONVERTS TO INTEGER IF IT IS
.MACRO DIGIT NOTDIG
CMP R0,#60 ;COMPARE TO ASC ZERO
BLT NOTDIG ;SKIP IF OUT OF RANGE
CMP R0,#71 ;COMPARE TO ASC 9
BGT NOTDIG ;SKIP IF OUT OF RANGE
BIC #60,R0 ;MASK OUT ASC BASE
.ENDM
;"CKSIGN" CHECKS FOR A - OR + CHARACTER AND SETS SIGN APPROPRIATELY
.MACRO CKSIGN ISSIGN,NTSIGN,SIGN
CMP #53,R0 ;IGNOR "+" CHARACTER
BEQ ISSIGN
CMP #55,R0 ;CHECK IF ITS A "-" CHAR.
BNE NTSIGN ;EXIT IF ITS NOT
INC SIGN ;ELSE SET SIGN NON-ZERO
JMP ISSIGN
.ENDM
;START OF "RELSCN"
RELSCN: MOV R0,-(SP) ;SAVE REGISTERS
MOV R1,-(SP)
MOV R2,-(SP)
MOV R3,-(SP)
CLR R2 ;RESET DIGIT COUNT
MOV #1,R3 ;SET DECIMAL POINT FLAG
[CONTINUATION OF "RELSCN"]
MOV #-1,R1 ;INDICATE NO DIGITS ENCOUNTERED
CLRF AC0 ;CLEAR THE NUMBER ACCUM
CLR MSIGN ;ASSUME MANTISSA POSITIVE
;PICK UP A CHARACTER AND CHECK FOR SIGN
PICK: MOVB (SG)+,R0 ;PICK UP A CHARACTER
TST R1 ;CHECK IF DIGIT ENCOUNTERED
BEQ CHKDG ;SKIP IF TRUE
CKSIGN PICK,CHKDG,MSIGN ;CHECK FOR + OR - SIGN
;CHECK IF CHARARCTER IS A DIGIT
CHKDG: DIGIT CHKDP ;SKIP TO CHKDP IF NOT A DIGIT
MULF TEN,AC0 ;MULT DIGIT SUM BY 10
ASH #2,R0 ;MULTIPLY INDEX BY 4
ADDF DGLST(R0),AC0 ;ADD THE F.P. TO ACCUM
CLR R1 ;INDICATE DIGIT ENCOUNTERED
SUB #4,R2 ;DECREMENT DIGIT COUNT
JMP PICK ;GO GET ANOTHER CHARACTER
;CHECK IF THE CHARACTER IS A DECIMAL POINT
CHKDP: CMP #56,R0 ;COMPARE CHARACTER TO DECIMAL PT
BNE RNORM ;SKIP IF NOT D.P.
TST R3 ;CHECK IF DECIMAL POINT ALREADY SET
BEQ RNORM ;IF RESET THIS MUST BE A THE END OF THE MANT.
CLR R2 ;START COUNTING FRACTIONAL DIGITS
CLR R3 ;INDICATE D.P. SET
CLR R1 ;INDICATE DIGIT ENCOUNTERED
JMP PICK ;GO GET ANOTHER CHARACTER
;CORRECT NUMBER FOR POWER OF TEN IF DIGITS FOUND
RNORM: TST R1 ;CHECK IF DIGITS FOUND
BNE CHKEX ;SKIP IF NONE
TST R3 ;CHECK IF DECIMAL POINT SET
BNE CHKEX ;DONT NORMALIZE IF NO D.P.
MULF TENLST(R2),AC0 ;CORRECT DECIMAL POINT
;CHECK IF E SIGN ENCOUNTERED
CHKEX: CMP #105,R0 ;COMPARE TO E CHARACTER
BNE CHKDN ;SKIP IF NOT E
TST R1 ;CHECK IF NO DIGITS BEFORE E
BEQ EXCN
LDF TENLST,AC0 ;SET AC0=1 IF EXPONENT BUT NO DIGITS
[CONTINUATION OF "RELSCN"]
CLR R1 ;INDICATE DIGITS ENCOUNTERED
EXCN: CLR ESIGN ;ASSUME EXPONENT POSITIVE
CLR R3 ;CLEAR EXPONENT ACCUMULATOR
MOVB (SG)+,R0 ;GET NEXT CHARACTER
CKSIGN PIC2,DIG2,ESIGN ;CHECK FOR SIGN CHARACTER
PIC2: MOVB (SG)+,R0 ;SIGN INCOUNTERED, GET NEXT CHAR.
DIG2: DIGIT NORM ;EXTRACT DIGIT
MUL #10.,R3 ;MULT EXPON REG BY 10.
ADD R0,R3 ;ADD DIGIT TO EXPONENT REG
JMP PIC2 ;GO GET ANOTHER CHARACTER
NORM: TST ESIGN ;CHECK SIGN OF EXPONENT
BEQ .+4
NEG R3 ;COMPLEMENT EXPONENT IF - SIGN
ASH #2,R3 ;MULT. INDEX BY 4 FOR F.P. NUMBERS
MULF TENLST(R3),AC0 ;ADJUST EXPONENT OF NUMBER
JMP CDONE ;EXIT ROUTINE
;CHECK IF END OF STRING OR COMMA ENCOUNTERED
CHKDN: TST R0 ;COMPARE CHARACTER TO A NULL CHARACTER
BEQ CDONE ;EXIT IF IT IS, THIS IS THE END OF THE STR
CMP #54,R0 ;COMPARE TO ","
BEQ CDONE ;EXIT IF IT IS
TST R1 ;TEST IF ANY DIGITS YET
BLT PICK ;IF NONE, KEEP SCANNING
;NO MORE DIGITS - APPLY CORRECT SIGN TO NUMBER
CDONE: DEC SG ;POINT TO BREAK CHARACTER
TST MSIGN ;TEST SIGN OF MANTISSA
BEQ .+4
NEGF AC0 ;COMPLEMENT NUMBER IF SIGN NEGATIVE
TST R1 ;TEST IF NO NUMBER ENCOUNTERED
BEQ .+4
SEC ;SET C REGISTER IF NO NUMBER FOUND
MOV (SP)+,R3 ;RESTORE REGISTERS
MOV (SP)+,R2
MOV (SP)+,R1
MOV (SP)+,R0
RTS PC ;RETURN
;END OF "RELSCN"
;"INTSCN"- STRING TO INTEGER NUMBER ROUTINE
;THE INTEGER NUMBER MUST BE OF THE FORM SIII WHERE S IS THE SIGN OF THE
;NUMBER, AND III IS THE INTEGER FIELD. ALL LEADING SPACES AND ZEROS
;ARE IGNORED. THE LOCATION OF THE FIRST BYTE OF THE STRING MUST BE
;LOADED INTO REGISTER SG BEFORE CALLING "INTSCN". AFTER EXECUTION,
;THIS ROUTINE LEAVES THE INTEGER NUMBER IN R0 AND SG POINTS TO
;THE BYTE FOLLOWING THE LAST DIGIT. THE C BIT IS USED TO INDICATE AN
;ERROR CONDITION. IF NO NUMBER WAS FOUND BEFORE ENCOUNTERING A COMMA
;OR NULL CHARACTER, THE C BIT IS SET. ALSO, IF THE INTEGER NUMBER IS
;TOO LARGE, THE C BIT IS SET, OTHERWISE THE C BIT IS CLEARED ON EXITING
;THIS ROUTINE. "INTSCN" IS CALLED USING THE PC.
;REGISTERS USED:
;
; R0,SG PASS ARGUMENTS AND ARE ALTERED
; AC0 IS GARBAGED
INTSCN: JSR PC,RELSCN ;CONVERT STRING NUMBER TO FLOATING POINT
BCC .+4
RTS PC ;EXIT IF NO NUMBER FOUND
STCFI AC0,R0 ;ELSE CONVERT NUMBER TO INTEGER
CFCC ;TRANSFER CODITIONAL CODES
RTS PC ;RETURN
;END OF "INTSCN"
;"CLRCMA"- ROUTINE TO CLEAR COMMA BREAK CHARACTER FROM STRING
;"CLRCMA" CAN BE CALLED FOLLOWING "RELSCN" TO ADJUST THE STRING
;POINTER IN SG TO SKIP OVER THE COMMA CHARACTER WHICH IS USED
;TO SEPARATE NUMBERS IN THE SAME INPUT STRING. SG MUST BE
;POINTING AT THE INPUT STRING. NO OTHER REGISTERS ARE EFFECTED.
CLRCMA: TSTB (SG) ;CHECK IF AT END OF STRING
BNE .+4
RTS PC ;RETURN IF END OF STRING
CMPB #54,(SG)+ ;COMPARE TO COMMA CHARACTER
BNE CLRCMA ;BRANCH IF IT ISN'T
RTS PC
;END OF "CLRCMA"
;"IDENT" - DECODES STRING COMMAND INTO FUNCTION NUMBER
;THIS PROGRAM HASHES THE FIRST WORD IN A GIVEN STRING AND USES THE HASH
;NUMBER AS A INDEX INTO A BYTE TABLE CONTAINING FUNCTION NUMBERS. THE
;CORRESPONDING FUNCTION NUMBER IS RETRIEVED AND USED AS A INDEX INTO
;A GIVEN TABLE OF STRINGS CONTAINING THE FUNCTION NAMES. IF A STRING
;MATCH IS OBTAINED, THE FUNCTION NUMBER IS RETURNED IN REGISTER R0. IF
;THE STRING IS FOUND TO CONTAIN NO CHARACTERS THE C BIT IS SET AND R1
;IS CLEARED. IF THE STRING CONTAINS CHARACTERS BUT NO MATCH IS FOUND,
;THE C BIT IS SET AND R1 IS SET TO -1. A CARRIAGE RETURN CHARACTER IS
;ASSUMED TO END THE INPUT STRING. A SAMPLE CALLING SEQUENCE FOLLOWS:
;
; MOV #HASHTB,R0 ;POINTER TO FUNCTION/HASH TABLE
; MOV #STGLST,R1 ;PTR TO TABLE OF PTRS TO STRINGS
; MOV #STRING,SG ;PTR TO INPUT STRING
; JSR PC,IDENT
; BCS ERROR
;
;IF IDENT IS SUCCESSFUL, SG IS LEFT POINTING AT THE BREAK CHARACTER
;FOLLOWING THE COMMAND WORD.
IDENT: MOV R2,-(SP) ;SAVE REGISTERS
MOV R3,-(SP)
MOV R4,-(SP)
CMPB #40,(SG)+ ;IGNOR ALL LEADING SPACE CHARACTERS
BEQ .-4
TSTB -(SG) ;POINT TO FIRST NON-SPACE CHARACTER
MOV SG,-(SP) ;SAVE STRING POINTER
CLR CARCNT ;COUNT NUMBER OF CHAR. HASHED TOGETHER
CLR R2 ;FORM HASH IN HERE
IDEN1: CMPB #15,(SG) ;CHECK IF END OF LINE = CR CHARACTER
BEQ IDEN2
CMPB #40,(SG) ;CHECK IF END OF WORD = SPACE CHARACTER
BEQ IDEN2
MOVB (SG)+,R3
ADD R3,R2 ;ELSE ADD CHARACTERS TOGETHER
INC CARCNT ;INDICATE ONE MORE CHAR. IN WORD
BR IDEN1
IDEN2: TST CARCNT ;CHECK IF ANY CHARACTERS FOUND
BNE IDEN3
CLR R1 ;INDICATE EMPTY LINE
BR IDEN8
IDEN3: MOV #1,R3 ;NEED THIS IF REHASH REQUIRED
BIC #177740,R2 ;USE 5 LSB AS HASH INDEX
MOV R2,OHASH ;SAVE ORIGINAL HASH NUMBER
IDEN4: ADD R0,R2 ;GET ADDR. INTO HASH TABLE
MOVB (R2),R2 ;GET INDEX INTO FUNCTION TABLE
MOV R2,HASH
BMI IDEN7 ;ILLEGAL INSTRUCTION IF MINUS
ASL R2 ;CONVERT TO WORD INDEX
ADD R1,R2 ;NOW HAVE POINTER TO FUNCTION NAME STG.
MOV (R2),R2
MOV (SP),SG ;GET POINTER TO START OF WORD
MOV CARCNT,R4 ;GET NUMBER OF CHARACTERS IN WORD
IDEN5: CMPB (R2)+,(SG)+ ;COMPARE STRINGS CHARACTER BY CHARACTER
BNE IDEN6 ;BRANCH IF NOT THE SAME
SOB R4,IDEN5
TSTB (R2) ;THIS SHOULD BE THE END OF THE NAME STG
BEQ IDNDNE ;EXIT IF STRINGS EXACTLY ALIKE
IDEN6: MUL #5,R3 ;NEED TO DETERMINE A NEW HASH NUMBER OF NAME
BIC #177600,R3
MOV R3,R2
ASH #-2,R2 ;THIS IS INCREMENT TO OLD HASH NUMBER
BEQ IDEN7 ;IF ZERO, WE LOOKED AT WHOLE TABLE ALREADY
ADD OHASH,R2 ;ELSE ADD ORIGINAL HASH INDEX
BIC #177740,R2
BR IDEN4 ;GO TRY MATCHING CHARACTERS AGAIN
IDEN7: MOV #-1,R1 ;INDICATE ILLEGAL INSTRUCTION
IDEN8: SEC
IDNDNE: MOV HASH,R0 ;RETURN FUNCTION NUMBER
MOV (SP)+,R4 ;LEAVE SG POINTING AT BREAK CHARACTER
MOV (SP)+,R4 ;RESTORE REGISTERS
MOV (SP)+,R3
MOV (SP)+,R2
RTS PC
OHASH: 0 ;ORIGINAL HASH NUMBER
HASH: 0 ;CURRENT HASH NUMBER
CARCNT: 0 ;NUMBER OF CHARACTERS IN COMMAND WORD
;END OF "IDENT"
;"FORMAT"&"RSTFOR" - ROUTINES TO SET AND RESTORE OUTPUT FORMAT
;THE TOTAL NUMBER OF CHARACTERS TO BE WRITTEN (WIDTH) SHOULD BE
;LOADED INTO R0 AND THE NUMBER OF DECIMAL DIGITS (DIGITS) SHOULD
;BE LOADED INTO R1 BEFORE CALLING THIS ROUTINE. IN ALL CASES,
;WIDTH SHOULD BE GREATER THAN OR EQUAL TO DIGIT+2. "FORMAT" IS
;CALLED BY USING THE PC.
;REGISTERS USED:
;
; R0,R1 PASS ARGUMENTS
; NO OTHER REGISTERS AFFECTED
FORMAT: MOV WIDTH,OLDW ;SAVE THE OLD WIDTH
MOV DIG,OLDD ; AND DIG
SUB #2,R0 ;SUBTRACT SPACES FOR SIGN AND . FROM WIDTH
MOV R0,WIDTH ;SAVE WIDTH OF I/O STRING - 2
MOV R1,DIG ;SAVE THE NUMBER OF DECI. DIGITS
CMP R0,R1 ;CHECK TO SEE THAT WIDTH.GE.DIGIT+2
BGE NFER ;SKIP IF SPACE ALLOWED, ELSE CORRECT
OUTSTR FERM ;TYPE OUT ERROR MESSAGE
MOV R1,WIDTH ;SET WIDTH=DIG+2
NFER: RTS PC ;RETURN
FERM: .ASCIZ /
FORMATTING ERROR
/
.EVEN
;"RSTFOR" - ROUTINE TO RESTORE LAST FORMAT
;THE PREVIOUS FORMAT BECOMES THE CURRENT FORMAT. THE CURRENT
;FORMAT IS LOST FOREVER. "RSTFOR" IS CALLED IN USING THE PC.
;REGISTERS USED: NONE
RSTFOR: MOV OLDW,WIDTH ;RESTORE WIDTH
MOV OLDD,DIG ;RESTORE DIG
RTS PC ;RETURN
;END OF "FORMAT" &"RSTFOR"
;"CVF" - FLOATING POINT NUMBER TO "F" FORMAT STRING ROUTINE
;"CVF" - THE STRING GENERATED BY THIS ROUTINE IS SIMILAR TO "F" FORMAT
;IN FORTRAN. IT IS ASSUMED THAT THE NUMBER TO BE CONVERTED IS IN
;REGISTER AC0 AND SG CONTAINS A POINTER TO THE FIRST BYTE OF THE
;OUTPUT STRING. THE NUMBER OF CHARACTERS WRITTEN SHOULD FIRST BE SET
;IN A CALL TO "FORMAT", ELSE THE DEFAULT VALUES ARE USED. IF THE
;INTEGER PART OF THE NUMBER EXCEEDS THE FORMAT LIMITS THE FIRST
;CHARACTER WRITTEN IS A ">". AFTER COMPLETION, "CVF" LEAVES A NULL
;CHARACTER FOLLOWING THE NUMBER STRING. REGISTER SG IS LEFT POINTING
;AT THE NULL CHARACTER.
;REGISTERS USED:
;
; SG,AC0 PASS ARGUMENTS AND ARE ALTERED
; AC1 IS GARBAGED
CVF: MOV R1,-(SP) ;SAVE REGISTER
MOV WIDTH,R1 ;GET THE TOTAL NUMBER OF CHAR TO BE WRITTEN
SUB DIG,R1 ;DETERMINE THE MAG. OF THE M.S. DIGIT
MOV R1,PT ;NOW HAVE # OF DIGITS BEFORE DECIMAL POINT
ASH #2,R1 ;X 4, USE AS INDEX INTO F.P. TABLE
NEG R1
MULF TENLST(R1),AC0 ;NORMALIZE NUMBER TO BETWEEN 0 AND .99999999
MOV WIDTH,R1 ;TOTAL # OF DIGITS TO R1
MOV R2,-(SP) ;SAVE THE REGISTERS
MOV R3,-(SP)
JSR PC,PRTF ;TYPE OUT THE DIGITS
MOVB #0,(SG) ;PUT A NULL CHARACTER AFTER THE STRING
MOV (SP)+,R3 ;RESTORE THE REGISTERS
MOV (SP)+,R2
MOV (SP)+,R1
RTS PC ;RETURN
;END OF "CVF"
;"CVE" - FLOATING POINT NUMBER TO "E" FORMAT STRING ROUTINE
;"CVE" - SAME OPERATION AS "CVF" EXCEPT THAT OUTPUT IN FORTRAN "E" FORMAT
CVE: MOV R1,-(SP)
MOV R2,-(SP) ;SAVE THE REGISTERS
MOV R3,-(SP)
CLR EXPON ;RESET EXPONENT COUNT
MOV #1,PT ;SET COUNT TO PRINT 1 NUMBER BEFORE DECIMAL PT
MOV WIDTH,R1 ;SET COUNT FOR TOTAL NUMBER OF DIGITS TO BE SENT
SUB #4,R1 ;ADJUST FOR EXPONENT
TSTF AC0 ;CHECK IF NUMBER IS ZERO
CFCC ;TRANSFER CONDITIONAL CODES TO CPU
BEQ EPRT ;START PRINTING IF NUMBER IS 0.0
STF AC0,NUM ;GET THE NUMBER TO BE CONVERTED
DEC EXPON ;ADJUST EXPONENT FOR PRINTING 1 INT. DIGIT
MOV NUM,R2 ;LOAD THE EXPONENT AND MSB OF THE NUMBER
BIC #100000,R2 ;CONVERT TO ABSOLUTE VALUE
SUB #150,R2 ;ADJUST EXPONENT DOWN
BGE .+4
CLR R2 ;LEAVE IT POSITIVE
MUL #233,R2 ;USE EXPONENT AND MSB AS INDEX INTO TEN TABLE
CMP R2,#76. ;COMPARE TO 1.0@38
BLE .+6
MOV #76.,R2 ;IF LARGER, REPLACE BY 1.0@38
SUB #38.,R2 ;SHIFT INDEX INTO RANGE OF -38 TO +38
ADD R2,EXPON ;ADJUST EXPONENT COUNT
ASH #2,R2 ;MULT INDEX BY 4 FOR FLOATING POINT NUMBERS
NEG R2
MULF TENLST(R2),AC0 ;NORMALIZE NUMBER INTO RANGE 0.0 TO 0.9999
STF AC0,AC1 ;GET ABSOLUTE VALUE OF NUMBER
ABSF AC1
CMPF TENLST,AC1 ;CHECK IF NUMBER LESS THAN 1.0
CFCC ;TRANSFER CONDITIONAL CODES TO CPU
BGT EPRT ;IF ITS BETWEEN 0.0 AND .99999, GO TO PNTF
MULF TENTH,AC0 ;ELSE MULT. BY 0.1 AND ADJUST EXPONENT
INC EXPON
[CONTINUATION OF "CVE"]
EPRT: JSR PC,PRTF ;GO PRINT MANTISSA
MOVB #105,(SG)+ ;PUT A "E" CHAR INTO THE STRING
MOVB #53,(SG)+ ;ASSUME EXPONENT POSITIVE A OUTPUT A "+"
MOV EXPON,R3 ;TEST SIGN OF EXPONENT
BGE XPRT ;SKIP IF POSITIVE
MOVB #55,-1(SG) ;REPLACE "+" WITH "-"
NEG R3 ;MAKE EXPONENT POSITIVE
XPRT: CLR R2 ;CLEAR FOR DIVISION
DIV #10.,R2 ;SEPARATES TENS AND UNITS DIGIT
BIS #60,R2 ;CONVERT TO ASC AND PUT IN I/O BUFFER
MOVB R2,(SG)+
BIS #60,R3
MOVB R3,(SG)+
MOVB #0,(SG) ;PUT IN A NULL CHARACTER
MOV (SP)+,R3 ;RESTORE THE REGISTERS
MOV (SP)+,R2
MOV (SP)+,R1
RTS PC ;RETURN
;END OF "CVE"
;"CVG" - FLOATING POINT NUMBER TO "E" OR "F" FORMAT STRING
;"CVG" - DETERMINES IF THE NUMBER IN AC0 CAN BE WRITTEN BY "CVF", IF
;IT CAN, THEN CVF IS CALLED, ELSE THE NUMBER IS PRINTED USING "CVE".
CVG: MOV R1,-(SP)
LDF AC0,AC1 ;COPY THE NUMBER
CFCC ;TRANSFER THE CONDITIONAL CODES TO CPU
ABSF AC1 ;CONVERT NUMBER TO ABSOLUTE VALUES
BEQ RUNF ;IF NUMBER = 0.0, EXECUTE CVF
MOV DIG,R1 ;GET THE NUMBER OF DECIMAL DIGITS TO BE TYPED
ASH #2,R1 ;MULT BY 4 TO USE A FLOATING POINT INDEX
MULF TENLST(R1),AC1 ;CHECK IF NUMBER SMALLER THAN 1.0@-DIG
CMPF TENLST,AC1 ;COMPARE TO 1.0
CFCC ;TRANSFER CONDITIONAL CODES TO CPU
BGT RUNE ;IF LESS THAN 1.0@-DIG, PRINT USING CVE
MOV WIDTH,R1 ;GET THE TOTAL NUMBER OF DIGITS TO BE PRINTED
ASH #2,R1 ;USE THIS AS A F.P. INDEX
NEG R1
MULF TENLST(R1),AC1 ;CHECK IF GREATER THAN WIDTH-DIG LONG
CMPF TENLST,AC1 ;COMPARE TO 1.0
CFCC ;TRANSFER CONDITIONAL CODES
BGE RUNF ;IF TOO LARGE, USE CVE
RUNE: JSR PC,CVE
MOV (SP)+,R1
RTS PC
RUNF: JSR PC,CVF
MOV (SP)+,R1
RTS PC
;END OF "CVG"
;"PRTF" - PRINTING ROUTINE USED BY "CVF", "CVE", & "CVG"
PRTF: TSTF AC0 ;TEST THE SIGN OF THE NUMBER
MOVB #40,MSIGN ;ASSUME SIGN POSITIVE
CFCC ;TRANSFER THE CONDITIONAL CODES TO CPU
ABSF AC0 ;CLEAR THE SIGN OF THE NUMBER
BGE .+10
MOVB #55,MSIGN ;IF NEGATIVE PUT IN "-" SIGN
MODF TEN,AC0 ;COMPUTE M.S. INTEGER DIGIT
CLR R3 ;INDICATE SIGN NOT YET WRITTEN
DIGLP: TST PT ;CHECK IF TIME TO PRINT DECIMAL POINT
BNE GETDG ;SKIP IF NOT
TST R3 ;HAVE WE PRINTED SIGN YET?
BNE WTDP ;SKIP IF WE HAVE
MOVB MSIGN,(SG)+ ;ELSE PRINT SIGN BEFORE DECIMAL POINT
INC R3 ;INDICATE SIGN PRINTED
WTDP: MOVB #56,(SG)+ ;PRINT DECIMAL POINT
GETDG: STCFI AC1,R2 ;SAVE M.S. INTEGER DIGIT
CFCC ;CHECK FOR NUMBER TOO LARGE TO INTEGERIZE
BCC CHKSZ
TOLGE: ADDF AC1,AC0 ;IF TWO LARGE, PUT IT BACK TOGETHER
MODF TENTH,AC0 ;SCALE DOWN AND TRY INTEGERIZING AGAIN
INC R1 ;PRINT OUT ONE MORE DIGIT
INC PT ;SHIFT DECIMAL POINT TO PUT IN EXTRA DIGIT
TST R3 ;CHECK IF SIGN AND D.P. ALREADY WRITTEN
BEQ GETDG ;GO CHECK IF IN RANGE IF NOT WRITTEN
CLR R3 ;CLEAR SIGN AND D.P.
SUB #2,SG ;ADJUST BYTE POINTER
JMP GETDG ;GO CHECK IF IN RANGE AGAIN
CHKSZ: TST R2 ;TEST INTEGER
BLT TOLGE ;IF TOO LARGE, GO SCALE AGAIN
CMP R2,#9. ;CHECK IF LESS THAN 9
BGT TOLGE ;SCALE IF GREATER THAN 9
MODF TEN,AC0 ;START COMPUTING NEXT INTEGER DIGIT
TST R3 ;HAVE WE PRINTED SIGN YET?
BNE SETBS ;SKIP IF WE HAVE
TST R2 ;CHECK IF LEADING ZERO
BEQ WTSP ;IF IT IS GO WRITE A SPACE CHARACTER
MOVB MSIGN,(SG)+ ;FIRST CHARACTER, NOW PRINT SIGN
INC R3 ;INDICATE SIGN PRINTED
SETBS: BIS #60,R2 ;SET ASC ZERO BASE
JMP WTCH
WTSP: MOVB #40,R2 ;WRITE A SPACE CHARACTER
WTCH: MOVB R2,(SG)+ ;PUT CHARACTER IN I/O BUFFER
DEC PT ;DECREMENT DECIMAL POINT COUNT
SOB R1,DIGLP ;DONE WITH CHARACTERS?
RTS PC ;RETURN
;END OF "PRTF"
;"CVI"&"CVO" - INTEGER NUMBER TO ASC STRING
;"CVI"&"CVO" CONVERT THE INTEGER LOADED INTO R0 INTO A ASCII STRING
;AND APPEND THE NUMBER STRING TO THE STRING POINTED TO BY SG. SG IS
;LEFT POINTING AT A NULL CHARACTER. A SAMPLE CALLING SEQUENCE
;FOLLOWS:
;
; MOV #NUM,R0 ;LOAD NUMBER TO BE CONVERTED
; MOV #STRG,SG ;POINT TO OUTPUT STRING
; JSR PC,CVI
;
;"CVI" DOES A DECIMAL CONVERSION, WHILE "CVO" WORKS IN BASE 8.
;REGISTERS USED:
;
; R0, SG PASS ARGUMENTS AND ARE ALTERED
CVI: MOV R2,-(SP) ;SAVE REGISTER
MOV #10.,R2 ;DO A DECIMAL CONVERSION
BR CVV
CVO: MOV R2,-(SP) ;SAVE REGISTER
MOV #8.,R2 ;DO A OCTAL CONVERSION
CVV: MOV R1,-(SP) ;SAVE REGISTER
TST R0 ;CHECK SIGN OF NUMBER
BGE ITISPL ;BRANCH IF POSITIVE
NEG R0 ;ELSE COMPLEMENT
MOVB #55,(SG)+ ;PUSH A "-" INTO STRING
ITISPL: JSR PC,DIVLP ;GO FORM STRING RECURSIVELY
CLRB (SG) ;POINT TO A NULL CHARACTER A END OF STG
MOV (SP)+,R1 ;RESTORE REGISTERS
MOV (SP)+,R2
RTS PC ;ALL DONE
DIVLP: MOV R0,R1 ;POSITION NUMBER FOR DIVISION
CLR R0 ;CLEAR FOR DIVISION
DIV R2,R0 ;GET LSD
ADD #60,R1 ;OR ASC BASE
MOVB R1,-(SP) ;SAVE DIGIT
TST R0
BEQ .+6 ;SKIP IF ALL DONE
JSR PC,DIVLP ;REPEAT RECURSIVELY
MOVB (SP)+,(SG)+ ;PUT DIGITS IN STRING
RTS PC
;END OF "CVI"
;LOCAL STORAGE AREA
MSIGN: 0 ;SIGN OF CURRENT NUMBER
ESIGN: 0 ;SIGN OF EXPONENT
EXPON: 0
NUM: .WORD 0,0
WIDTH: 8. ;DEFAULT NUMBER OF CHARACTERS IN OUTPUT STRING
DIG: 3 ;DEFAULT NUMBER OF DECIMAL DIGITS
OLDW: 8. ;OLD VALUES OF WIDTH AND DIG
OLDD: 3
PT: 0 ;NUMBER OF DIGITS BEFORE DECIMAL POINT
;SYSTEM LINE BUFFERS
INBUF: .BLKW 42.
OUTBUF: .BLKW 42.
;TABLE OF F.P. DIGITS FROM 0.0 TO 9.0
DGLST: .WORD 0, 0, 40200, 0, 40400, 0, 40500, 0
.WORD 40600, 0, 40640, 0, 40700, 0, 40740, 0
.WORD 41000, 0, 41020, 0
;TABLE OF POWERS OF TEN
.WORD 531,143735, 1410, 16352, 2252, 22044, 3124,126455
.WORD 4004,166074, 4646, 23513, 5517,130436, 6401,147263
.WORD 7242, 41140, 10112,151370, 10775,103666, 11636, 72321
.WORD 12506, 11006, 13367,113210, 14232,137025, 15101, 66632
.WORD 15761,144400, 16627, 16640, 17474,162410, 20354, 17112
.WORD 21223,111356, 22070, 73652, 22746,112625, 23620, 16575
.WORD 24464, 22334, 25341, 27023, 26214,136314, 27057,165777
.WORD 27733,163377, 30611, 70137, 31453,146167, 32326,137625
.WORD 33206, 33675, 34047,142654, 34721,133430, 35603, 11157
.WORD 36443,153412
TENTH: .WORD 37314,146315
TENLST: .WORD 40200, 0
TEN: .WORD 41040, 0
.WORD 41710, 0, 42572, 1, 43434, 40000, 44303, 50000
.WORD 45164, 22001, 46030,113200, 46676,136040, 47556, 65451
.WORD 50425, 1371, 51272, 41670, 52150,152246, 53021,102347
.WORD 53665,163041, 54543, 57652, 55416, 15712, 56261,121275
.WORD 57136, 5554, 60012,143443, 60655, 74354, 61530,153447
.WORD 62407,103170, 63251, 64027, 64123,141034, 65004, 54522
.WORD 65645, 67646, 66516,145620, 67401, 37472, 70241,107410
.WORD 71111,171312, 71774, 67575, 72635,142656, 73505, 33432
.WORD 74366,102340, 75232, 11414, 76100,113717, 76760,136703
.WORD 77626, 73232
;END OF "IO" PROGRAM